///////////////////////////////////////////////////////////////////////////////
// FILE:          GCode.h
// PROJECT:       Micro-Manager
// SUBSYSTEM:     DeviceAdapters
//-----------------------------------------------------------------------------
// DESCRIPTION:   An Arduino GCode implementation of an XY and Z stage.  This started
//                as a copy of the example implementation of the demo camera.
//                
// AUTHOR:        Jay Longson, jay.longson@gmail.com, Rich Gibson, rich.gibson@gmail.com,
//                Gene Cooper, gene@fourchambers.org 3/2011
//
// COPYRIGHT:     TBD - DemoCamera base was
//                University of California, San Francisco, 2006
//                100X Imaging Inc, 2008
//
// LICENSE:       This file is distributed under the BSD license.
//                License text is included with the source distribution.
//
//                This file is distributed in the hope that it will be useful,
//                but WITHOUT ANY WARRANTY; without even the implied warranty
//                of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
//                IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//                CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//                INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES.
//
// CVS:           $Id: DemoCamera.h 3785 2010-01-16 06:21:07Z nico $
//

#ifndef _GCODE_H_
#define _GCODE_H_

#include "../../MMDevice/DeviceBase.h"
#include "../../MMDevice/ImgBuffer.h"
#include "../../MMDevice/DeviceThreads.h"
#include <string>
#include <map>

//////////////////////////////////////////////////////////////////////////////
// Error codes
//
#define ERR_UNKNOWN_MODE         102
#define ERR_UNKNOWN_POSITION     103

#define ERR_PORT_CHANGE_FORBIDDEN    10004
#define ERR_SET_POSITION_FAILED      10005
#define ERR_INVALID_STEP_SIZE        10006
#define ERR_INVALID_MODE             10008
#define ERR_UNRECOGNIZED_ANSWER      10009
#define ERR_UNSPECIFIED_ERROR        10010
#define ERR_COMMAND_ERROR            10011
#define ERR_PARAMETER_ERROR          10012
#define ERR_RECEIVE_BUFFER_OVERFLOW  10013
#define ERR_COMMAND_OVERFLOW         10014
#define ERR_PROCESSING_INHIBIT       10015
#define ERR_PROCESSING_STOP_ERROR    10016
#define ERR_ND_OUTOFBOUNDS           10017

#define ERR_OFFSET 10100


//////////////////////////////////////////////////////////////////////////////
// GCodeZAxis class
// Control the Z (Focus) Axis 
//////////////////////////////////////////////////////////////////////////////

class GCodeZAxis : public CStageBase<GCodeZAxis>
{
public:
   GCodeZAxis();
   ~GCodeZAxis();

   bool Busy() {return busy_;}
   void GetName(char* pszName) const;

   int Initialize();
   int Shutdown();
     
   // Stage API
   int SetPositionUm(double pos);
   int GetPositionUm(double& pos);
   double GetStepSize() {return stepSize_Um_;}
   int SetPositionSteps(long steps);
   int GetPositionSteps(long& steps); 
   int SetOrigin();
   int GetLimits(double& lower, double& upper);
   int Move(double /*v*/) {return DEVICE_OK;}

   // action interface
   // ----------------
   int OnPosition(MM::PropertyBase* pProp, MM::ActionType eAct);
   int OnPort(MM::PropertyBase* pProp, MM::ActionType eAct);
   int OnStepSizeUm(MM::PropertyBase* pProp, MM::ActionType eAct);

private:
   int ExecuteCommand(const std::string& cmd, std::string& response);

   std::string port_;
   long curSteps_ ;
   double answerTimeoutMs_;

   // these are from the original demo camera code
   void SetIntensityFactor(double pos);
   double stepSize_Um_;
   double pos_um_;
   bool busy_;
   bool initialized_;
   double lowerLimit_;
   double upperLimit_;
};

//////////////////////////////////////////////////////////////////////////////
// GCodeZAxis class
// Simulation of the single axis stage
//////////////////////////////////////////////////////////////////////////////

class GCodeXYStage : public CXYStageBase<GCodeXYStage>
{
public:
   GCodeXYStage();
   ~GCodeXYStage();

   bool Busy() {return busy_;}
   void GetName(char* pszName) const;

   int Initialize();
   int Shutdown();
     
   // XYStage API
   /* Note that only the Set/Get PositionStep functions are implemented in the adapter
    * It is best not to override the Set/Get PositionUm functions in DeviceBase.h, since
    * those implement corrections based on whether or not X and Y directionality should be mirrored
    * and based on a user defined origin
    */
   // This must be correct or the conversions between steps and Um will go wrong
   virtual double GetStepSize() {return stepSize_um_;}
   virtual int SetPositionSteps(long x, long y)
   {
      posX_um_ = x * stepSize_um_;
      posY_um_ = y * stepSize_um_;
      return DEVICE_OK;
   }
   virtual int GetPositionSteps(long& x, long& y)
   {
      x = (long)(posX_um_ / stepSize_um_);
      y = (long)(posY_um_ / stepSize_um_);
      return DEVICE_OK;
   }
   int SetRelativePositionSteps(long x, long y)                                                           
   {                                                                                                      
      long xSteps, ySteps;                                                                                
      GetPositionSteps(xSteps, ySteps);                                                   

      return this->SetPositionSteps(xSteps+x, ySteps+y);                                                  
   } 
   virtual int Home() {return DEVICE_OK;}
   virtual int Stop() {return DEVICE_OK;}
   // This sets the 0,0 position of the adapter to the current position.  If possible, the stage controller itself
   // should also be set to 0, 0
   // Note that this differs form the function SetAdapterOrigin(), which sets the coordinate system used by the adapter
   // to values different from the system used by the stage controller
   virtual int SetOrigin() {return DEVICE_OK;}//jizhen 4/12/2007
   virtual int GetLimits(double& lower, double& upper)
   {
      lower = lowerLimit_;
      upper = upperLimit_;
      return DEVICE_OK;
   }
   virtual int GetLimitsUm(double& xMin, double& xMax, double& yMin, double& yMax)
   {
      xMin = lowerLimit_; xMax = upperLimit_;
      yMin = lowerLimit_; yMax = upperLimit_;
      return DEVICE_OK;
   }

   virtual int GetStepLimits(long& /*xMin*/, long& /*xMax*/, long& /*yMin*/, long& /*yMax*/)
   {
      return DEVICE_UNSUPPORTED_COMMAND;
   }
   double GetStepSizeXUm() {return stepSize_um_;}
   double GetStepSizeYUm() {return stepSize_um_;}
   int Move(double /*vx*/, double /*vy*/) {return DEVICE_OK;}

   // action interface
   // ----------------
   int OnPosition(MM::PropertyBase* pProp, MM::ActionType eAct);

private:
   double stepSize_um_;
   double posX_um_;
   double posY_um_;
   bool busy_;
   bool initialized_;
   double lowerLimit_;
   double upperLimit_;
};
//////////////////////////////////////////////////////////////////////

#endif //_GCODE_H_
